#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
高级反调试系统 - 实现检测和防御调试器、虚拟机和代码篡改
通过多种技术保护应用程序免受逆向工程和调试分析
"""
import os
import sys
import time
import platform
import subprocess
import ctypes
import random
import hashlib
import threading
import psutil
import inspect
from typing import Dict, List, Tuple, Optional, Any

# 导入项目模块
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))  # noqa
from utils import Logger
from utils.file_utils import FileUtils

class AntiDebugger:
    """高级反调试系统核心类"""
    def __init__(self):
        """初始化反调试系统"""
        self.file_utils = FileUtils()
        
        # 反调试配置
        self.anti_debug_config = {
            "enable_debug_detection": True,
            "enable_vm_detection": True,
            "enable_code_integrity_check": True,
            "enable_time_check": True,
            "enable_process_check": True,
            "detection_level": "medium",  # low, medium, high
            "response_strategy": "exit",  # log, warn, exit, fake_data
            "check_interval": 1.0,  # 秒
            "time_threshold": 0.1,  # 秒，时间检查阈值
            "critical_files": []  # 需要检查完整性的关键文件列表
        }
        
        # 线程锁
        self.check_lock = threading.Lock()
        
        # 监控线程
        self.monitor_thread = None
        self._stop_monitor = False
        
        # 初始化系统类型
        self.system_type = platform.system()
        
        # 初始化代码哈希缓存
        self.code_hashes = {}
        
        Logger.log_info("高级反调试系统初始化完成")
    
    def start_monitoring(self) -> bool:
        """启动持续监控"""
        try:
            # 检查反调试功能是否启用
            if not self.anti_debug_config["enable_debug_detection"]:
                Logger.log_info("反调试功能未启用，跳过监控启动")
                return False
            
            # 如果监控线程已经在运行，先停止它
            if self.monitor_thread and self.monitor_thread.is_alive():
                self.stop_monitoring()
            
            # 重置停止标志
            self._stop_monitor = False
            
            # 创建并启动监控线程
            self.monitor_thread = threading.Thread(target=self._monitor_loop, daemon=True)
            self.monitor_thread.start()
            
            Logger.log_info("反调试监控已启动")
            return True
        except Exception as e:
            Logger.log_error(f"启动反调试监控失败: {str(e)}")
            return False
    
    def stop_monitoring(self) -> bool:
        """停止持续监控"""
        try:
            # 设置停止标志
            self._stop_monitor = True
            
            # 等待监控线程结束
            if self.monitor_thread and self.monitor_thread.is_alive():
                self.monitor_thread.join(timeout=3.0)
                
                # 如果线程仍在运行，记录警告
                if self.monitor_thread.is_alive():
                    Logger.log_warning("反调试监控线程未能正常终止")
                    return False
            
            Logger.log_info("反调试监控已停止")
            return True
        except Exception as e:
            Logger.log_error(f"停止反调试监控失败: {str(e)}")
            return False
    
    def _monitor_loop(self) -> None:
        """监控循环，定期执行各种检测"""
        try:
            while not self._stop_monitor:
                # 执行各种检测
                self._detect_debugger()
                
                if self.anti_debug_config["enable_vm_detection"]:
                    self._detect_virtual_machine()
                
                if self.anti_debug_config["enable_code_integrity_check"]:
                    self._check_code_integrity()
                
                if self.anti_debug_config["enable_process_check"]:
                    self._check_suspicious_processes()
                
                # 等待下一次检查
                wait_time = self.anti_debug_config["check_interval"] + random.uniform(-0.1, 0.1)  # 添加随机波动
                start_time = time.time()
                while time.time() - start_time < wait_time and not self._stop_monitor:
                    time.sleep(0.1)  # 小间隔检查是否需要停止
        except Exception as e:
            Logger.log_error(f"反调试监控循环发生错误: {str(e)}")
    
    def _detect_debugger(self) -> bool:
        """检测调试器是否存在"""
        try:
            with self.check_lock:
                is_debugged = False
                
                # 根据操作系统类型选择不同的检测方法
                if self.system_type == "Windows":
                    is_debugged = self._windows_detect_debugger()
                elif self.system_type == "Linux":
                    is_debugged = self._linux_detect_debugger()
                elif self.system_type == "Darwin":  # macOS
                    is_debugged = self._macos_detect_debugger()
                
                # 使用通用的Python级检测
                is_debugged = is_debugged or self._python_detect_debugger()
                
                # 如果检测到调试器，执行响应策略
                if is_debugged:
                    self._handle_detection("调试器检测")
                
                return is_debugged
        except Exception as e:
            Logger.log_error(f"调试器检测发生错误: {str(e)}")
            return False
    
    def _windows_detect_debugger(self) -> bool:
        """Windows系统调试器检测"""
        try:
            # 使用Windows API检测调试器
            kernel32 = ctypes.windll.kernel32
            
            # 方法1: 使用IsDebuggerPresent API
            if kernel32.IsDebuggerPresent():
                Logger.log_warning("检测到调试器 (IsDebuggerPresent)")
                return True
            
            # 方法2: 使用CheckRemoteDebuggerPresent API
            process_handle = kernel32.GetCurrentProcess()
            debugged = ctypes.c_bool()
            if kernel32.CheckRemoteDebuggerPresent(process_handle, ctypes.byref(debugged)) and debugged.value:
                Logger.log_warning("检测到调试器 (CheckRemoteDebuggerPresent)")
                return True
            
            # 方法3: 检查PEB结构中的BeingDebugged字段
            # 这是一个更高级的检测方法，需要直接访问进程环境块
            if self.anti_debug_config["detection_level"] == "high":
                # 获取当前进程句柄
                process_handle = kernel32.OpenProcess(0x0400, False, os.getpid())
                
                if process_handle:
                    # 获取PEB地址
                    peb_address = ctypes.c_void_p()
                    if kernel32.ReadProcessMemory(process_handle, ctypes.c_void_p(0x7FFDF000),  # 假设的PEB地址，实际应动态获取
                                                ctypes.byref(peb_address), ctypes.sizeof(peb_address), None):
                        # 读取BeingDebugged字段
                        being_debugged = ctypes.c_byte()
                        if kernel32.ReadProcessMemory(process_handle, ctypes.c_void_p(ctypes.cast(peb_address, ctypes.c_void_p).value + 2),
                                                    ctypes.byref(being_debugged), ctypes.sizeof(being_debugged), None):
                            if being_debugged.value != 0:
                                Logger.log_warning("检测到调试器 (PEB BeingDebugged)")
                                return True
                    
                    kernel32.CloseHandle(process_handle)
            
            return False
        except Exception as e:
            Logger.log_error(f"Windows调试器检测发生错误: {str(e)}")
            return False
    
    def _linux_detect_debugger(self) -> bool:
        """Linux系统调试器检测"""
        try:
            # 方法1: 检查/proc/self/status文件中的TracerPid字段
            try:
                with open("/proc/self/status", "r") as f:
                    for line in f:
                        if line.startswith("TracerPid:"):
                            tracer_pid = int(line.split(":")[1].strip())
                            if tracer_pid != 0:
                                Logger.log_warning(f"检测到调试器 (TracerPid={tracer_pid})")
                                return True
                            break
            except Exception:
                pass
            
            # 方法2: 检查进程的ppid是否为调试器进程
            if self.anti_debug_config["detection_level"] in ["medium", "high"]:
                try:
                    ppid = os.getppid()
                    # 检查父进程是否为常见的调试器进程名
                    proc_name = self._get_process_name(ppid)
                    if proc_name and proc_name.lower() in ["gdb", "lldb", "strace"]:
                        Logger.log_warning(f"检测到调试器 (父进程={proc_name})")
                        return True
                except Exception:
                    pass
            
            return False
        except Exception as e:
            Logger.log_error(f"Linux调试器检测发生错误: {str(e)}")
            return False
    
    def _macos_detect_debugger(self) -> bool:
        """macOS系统调试器检测"""
        try:
            # 方法1: 使用sysctl检测
            try:
                # 尝试导入sysctl模块
                import sysctl
                try:
                    # 检查是否有调试器附加
                    if sysctl.SYSCTL_KERN_PROC_PROC == 0:
                        Logger.log_warning("检测到调试器 (sysctl)")
                        return True
                except Exception:
                    pass
            except ImportError:
                # 如果没有sysctl模块，尝试使用其他方法
                pass
            
            # 方法2: 使用lldb命令检查
            if self.anti_debug_config["detection_level"] in ["medium", "high"]:
                try:
                    result = subprocess.run(["lldb", "--attach-pid", str(os.getpid()), "--batch"],
                                          stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=1)
                    if result.returncode == 0:
                        Logger.log_warning("检测到调试器 (lldb附加)")
                        return True
                except Exception:
                    pass
            
            return False
        except Exception as e:
            Logger.log_error(f"macOS调试器检测发生错误: {str(e)}")
            return False
    
    def _python_detect_debugger(self) -> bool:
        """Python级调试器检测"""
        try:
            # 方法1: 检查sys.gettrace()
            if hasattr(sys, 'gettrace') and sys.gettrace() is not None:
                Logger.log_warning("检测到Python调试器 (sys.gettrace)")
                return True
            
            # 方法2: 时间检查 - 检测单步执行
            if self.anti_debug_config["enable_time_check"]:
                start_time = time.time()
                # 执行一些快速操作
                for _ in range(10000):
                    _ = 1 + 1
                end_time = time.time()
                
                # 如果执行时间过长，可能被单步调试
                if end_time - start_time > self.anti_debug_config["time_threshold"]:
                    Logger.log_warning(f"检测到可能的单步调试 (执行时间={end_time - start_time:.6f}秒)")
                    return True
            
            # 方法3: 检查常见的Python调试器模块
            if self.anti_debug_config["detection_level"] == "high":
                debuggers = ["pdb", "ipdb", "pydevd", "pudb", "winpdb", "debugpy"]
                for debugger in debuggers:
                    if debugger in sys.modules:
                        Logger.log_warning(f"检测到Python调试器模块: {debugger}")
                        return True
            
            return False
        except Exception as e:
            Logger.log_error(f"Python调试器检测发生错误: {str(e)}")
            return False
    
    def _detect_virtual_machine(self) -> bool:
        """检测虚拟机环境"""
        try:
            with self.check_lock:
                is_vm = False
                
                # 根据操作系统类型选择不同的检测方法
                if self.system_type == "Windows":
                    is_vm = self._windows_detect_vm()
                elif self.system_type == "Linux":
                    is_vm = self._linux_detect_vm()
                elif self.system_type == "Darwin":  # macOS
                    is_vm = self._macos_detect_vm()
                
                # 如果检测到虚拟机，执行响应策略
                if is_vm:
                    self._handle_detection("虚拟机检测")
                
                return is_vm
        except Exception as e:
            Logger.log_error(f"虚拟机检测发生错误: {str(e)}")
            return False
    
    def _windows_detect_vm(self) -> bool:
        """Windows系统虚拟机检测"""
        try:
            vm_signatures = [
                # 常见虚拟机的设备名、服务名、注册表键等
                "VBox", "VMware", "VirtualBox", "QEMU", "Xen", "Parallels",
                "VMware Tools", "Virtual Machine", "VMware Workstation"
            ]
            
            # 方法1: 检查系统信息
            try:
                system_info = platform.platform()
                for signature in vm_signatures:
                    if signature.lower() in system_info.lower():
                        Logger.log_warning(f"检测到虚拟机特征 (system_info: {signature})")
                        return True
            except Exception:
                pass
            
            # 方法2: 检查环境变量
            if self.anti_debug_config["detection_level"] in ["medium", "high"]:
                try:
                    for key, value in os.environ.items():
                        for signature in vm_signatures:
                            if signature.lower() in key.lower() or signature.lower() in value.lower():
                                Logger.log_warning(f"检测到虚拟机特征 (env_var: {signature})")
                                return True
                except Exception:
                    pass
            
            return False
        except Exception as e:
            Logger.log_error(f"Windows虚拟机检测发生错误: {str(e)}")
            return False
    
    def _linux_detect_vm(self) -> bool:
        """Linux系统虚拟机检测"""
        try:
            vm_signatures = [
                "hypervisor", "virtual", "vmware", "vbox", "qemu", "xen", "kvm"
            ]
            
            # 方法1: 检查/sys/class/dmi/id/product_name
            try:
                with open("/sys/class/dmi/id/product_name", "r") as f:
                    product_name = f.read().lower()
                    for signature in vm_signatures:
                        if signature in product_name:
                            Logger.log_warning(f"检测到虚拟机特征 (product_name: {signature})")
                            return True
            except Exception:
                pass
            
            # 方法2: 检查/proc/cpuinfo
            try:
                with open("/proc/cpuinfo", "r") as f:
                    cpuinfo = f.read().lower()
                    for signature in vm_signatures:
                        if signature in cpuinfo:
                            Logger.log_warning(f"检测到虚拟机特征 (cpuinfo: {signature})")
                            return True
            except Exception:
                pass
            
            return False
        except Exception as e:
            Logger.log_error(f"Linux虚拟机检测发生错误: {str(e)}")
            return False
    
    def _macos_detect_vm(self) -> bool:
        """macOS系统虚拟机检测"""
        try:
            # 方法1: 检查系统信息
            try:
                system_info = platform.platform().lower()
                if "virtualbox" in system_info or "vmware" in system_info or "parallels" in system_info:
                    Logger.log_warning("检测到虚拟机特征 (system_info)")
                    return True
            except Exception:
                pass
            
            return False
        except Exception as e:
            Logger.log_error(f"macOS虚拟机检测发生错误: {str(e)}")
            return False
    
    def _check_code_integrity(self) -> bool:
        """检查代码完整性"""
        try:
            with self.check_lock:
                is_tampered = False
                
                # 检查关键文件的完整性
                for file_path in self.anti_debug_config["critical_files"]:
                    if os.path.exists(file_path):
                        current_hash = self._calculate_file_hash(file_path)
                        
                        # 如果是第一次检查，记录哈希值
                        if file_path not in self.code_hashes:
                            self.code_hashes[file_path] = current_hash
                        # 否则，比较哈希值
                        elif self.code_hashes[file_path] != current_hash:
                            Logger.log_warning(f"检测到文件被篡改: {file_path}")
                            is_tampered = True
                            break
                
                # 如果检测到代码被篡改，执行响应策略
                if is_tampered:
                    self._handle_detection("代码完整性检查")
                
                return is_tampered
        except Exception as e:
            Logger.log_error(f"代码完整性检查发生错误: {str(e)}")
            return False
    
    def _calculate_file_hash(self, file_path: str) -> str:
        """计算文件的哈希值"""
        try:
            hash_obj = hashlib.sha256()
            with open(file_path, 'rb') as f:
                # 分块读取文件以处理大文件
                for chunk in iter(lambda: f.read(4096), b''):
                    hash_obj.update(chunk)
            return hash_obj.hexdigest()
        except Exception as e:
            Logger.log_error(f"计算文件哈希值失败: {str(e)}")
            return ""
    
    def _check_suspicious_processes(self) -> bool:
        """检查可疑进程"""
        try:
            with self.check_lock:
                has_suspicious = False
                
                # 常见的逆向工程和调试工具进程名
                suspicious_processes = [
                    "idaq", "ida64", "idag", "idaw",  # IDA Pro
                    "ghidra", "dnspy", "windbg", "ollydbg", "x64dbg",
                    "gdb", "lldb", "strace", "ltrace", "objdump", "readelf",
                    "strings", "hexdump", "radare2", "r2", "angr", "qemu",
                    "virtualbox", "vmware", "parallels", "wireshark", "tcpdump"
                ]
                
                # 获取当前所有进程
                try:
                    for proc in psutil.process_iter(['name']):
                        try:
                            proc_name = proc.info['name'].lower()
                            for suspicious in suspicious_processes:
                                if suspicious in proc_name:
                                    Logger.log_warning(f"检测到可疑进程: {proc_name}")
                                    has_suspicious = True
                                    break
                        except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
                            pass
                except Exception:
                    pass
            
            # 如果检测到可疑进程，执行响应策略
            if has_suspicious:
                self._handle_detection("可疑进程检测")
            
            return has_suspicious
        except Exception as e:
            Logger.log_error(f"可疑进程检查发生错误: {str(e)}")
            return False
    
    def _handle_detection(self, detection_type: str) -> None:
        """处理检测结果，根据配置执行不同的响应策略"""
        strategy = self.anti_debug_config["response_strategy"]
        
        if strategy == "log":
            # 仅记录日志
            Logger.log_info(f"{detection_type} - 仅记录日志")
        elif strategy == "warn":
            # 记录警告并可能显示警告消息
            Logger.log_warning(f"{detection_type} - 发出警告")
            # 可以在这里添加显示警告消息的代码
        elif strategy == "exit":
            # 记录错误并退出应用程序
            Logger.log_error(f"{detection_type} - 执行退出策略")
            # 优雅地清理资源
            self.stop_monitoring()
            # 退出应用程序
            sys.exit(1)
        elif strategy == "fake_data":
            # 提供虚假数据而不是真实数据
            Logger.log_warning(f"{detection_type} - 执行虚假数据策略")
            # 可以在这里修改全局变量或状态，提供虚假数据
        else:
            # 默认策略：记录警告
            Logger.log_warning(f"{detection_type} - 使用默认策略")
    
    def _get_process_name(self, pid: int) -> Optional[str]:
        """获取进程名"""
        try:
            proc = psutil.Process(pid)
            return proc.name()
        except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
            return None
    
    def add_critical_file(self, file_path: str) -> bool:
        """添加关键文件到完整性检查列表"""
        try:
            if not os.path.exists(file_path):
                Logger.log_error(f"文件不存在: {file_path}")
                return False
            
            if file_path not in self.anti_debug_config["critical_files"]:
                self.anti_debug_config["critical_files"].append(file_path)
                # 预先计算哈希值
                self.code_hashes[file_path] = self._calculate_file_hash(file_path)
                Logger.log_info(f"添加关键文件到完整性检查: {file_path}")
            
            return True
        except Exception as e:
            Logger.log_error(f"添加关键文件失败: {str(e)}")
            return False
    
    def set_config(self, config: Dict) -> bool:
        """设置反调试配置"""
        try:
            with self.check_lock:
                # 验证配置项
                for key, value in config.items():
                    if key in self.anti_debug_config:
                        # 根据配置项类型进行验证
                        if key == "detection_level" and value not in ["low", "medium", "high"]:
                            Logger.log_error(f"无效的检测级别: {value}")
                            continue
                        if key == "response_strategy" and value not in ["log", "warn", "exit", "fake_data"]:
                            Logger.log_error(f"无效的响应策略: {value}")
                            continue
                        if key in ["check_interval", "time_threshold"] and not isinstance(value, (int, float)):
                            Logger.log_error(f"无效的时间值: {value}")
                            continue
                        
                        # 更新配置
                        self.anti_debug_config[key] = value
                        Logger.log_info(f"更新反调试配置: {key} = {value}")
                    else:
                        Logger.log_warning(f"未知的配置项: {key}")
                
                return True
        except Exception as e:
            Logger.log_error(f"设置反调试配置失败: {str(e)}")
            return False

if __name__ == "__main__":
    # 示例用法
    anti_debugger = AntiDebugger()
    
    # 添加关键文件
    anti_debugger.add_critical_file("example.py")
    
    # 设置配置
    anti_debugger.set_config({
        "detection_level": "high",
        "response_strategy": "log",  # 仅记录日志，实际应用中可以改为"exit"
        "check_interval": 0.5
    })
    
    # 启动监控
    anti_debugger.start_monitoring()
    
    # 主循环
    try:
        while True:
            # 应用程序的主要逻辑
            time.sleep(1)
    except KeyboardInterrupt:
        # 停止监控
        anti_debugger.stop_monitoring()
        print("反调试监控已停止")